#include <iostream>
#include <unistd.h>
#include <vector>
#include <cstdio>
#include "Thread.hpp"

// 应用方的视角
std::string GetThreadName()
{
    static int number = 1;
    char name[64];
    snprintf(name, sizeof(name), "Thread-%d", number++);
    return name;
}

void Print(int num)
{
    while (num)
    {
        std::cout << "hello world: " << num-- << std::endl;
        sleep(1);
    }
}

int ticket = 10000; // 全局的共享资源
// 共享资源了
// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 锁就有了，被定义并初始化了，这个锁也是全局的哦！！

// 加锁：
// 1. 我们要尽可能的给少的代码块加锁
// 2. 一般加锁，都是给临界区加锁
void GetTicket(std::string name)
{
    while (true)
    {
        // 2. 是由程序员自己保证的！规则都必须先申请锁
        // 3. 根据互斥的定义，任何时刻，只允许一个线程申请锁成功！多个线程申请锁失败，失败的线程怎么办？在mutex上进行阻塞，本质就是等待！
        //pthread_mutex_lock(&mutex); // 1. 申请锁本身是安全的，原子的，为什么？
        if (ticket > 0) // 4. 一个线程在临界区中访问临界资源的时候，可不可能发生切换?可能，完全允许！！
        {
            // 充当抢票花费的时间
            usleep(1000);
            printf("%s get a ticket: %d\n", name.c_str(), ticket);
            ticket--;
            //pthread_mutex_unlock(&mutex);
        }
        else
        {
            //pthread_mutex_unlock(&mutex);
            break;
        }
        // 实际情况，还有后续的动作， TODO?
    }
}


int main()
{
    //pthread_mutex_t mutex;
    //pthread_mutex_init(&mutex, nullptr);

    std::string name1 = GetThreadName();
    Thread<std::string> t1(name1, GetTicket, name1);

    std::string name2 = GetThreadName();
    Thread<std::string> t2(name2, GetTicket, name2);

    std::string name3 = GetThreadName();
    Thread<std::string> t3(name3, GetTicket, name3);

    std::string name4 = GetThreadName();
    Thread<std::string> t4(name4, GetTicket, name4);

    t1.Start();
    t2.Start();
    t3.Start();
    t4.Start();

    t1.Join();
    t2.Join();
    t3.Join();
    t4.Join();

    //pthread_mutex_destroy(&mutex);

    // Thread<int> t(GetThreadName(), Print, 10);

    // t.Start();

    // t.Join();

    // 这不就是：先描述，在组织
    // const int num = 5;
    // std::vector<Thread> threads;

    // for (int i = 0; i < num; i++)
    // {
    //     threads.push_back(Thread(Print, GetThreadName()));
    // }
    // for (auto &t : threads)
    // {
    //     std::cout << t.ThreadName() << ", is running: " << t.IsRunning() << std::endl;
    // }

    // for (auto &t : threads)
    // {
    //     t.Start();
    // }

    // for (auto &t : threads)
    // {
    //     std::cout << t.ThreadName() << ", is running: " << t.IsRunning() << std::endl;
    // }

    // for (auto &t : threads)
    // {
    //     t.Join();
    // }

    // Thread t(Print, GetThreadName());
    // std::cout << "is thread running? " << t.IsRunning() << std::endl;

    // t.Start();

    // std::cout << "is thread running? " << t.IsRunning() << std::endl;

    // t.Join();
    return 0;
}